using Microsoft.Extensions.Logging;
using System.Net;
using System.Net.Sockets;
using Uantek.Device.Communication.Models;

namespace Uantek.Device.Communication.Protocols.Transports
{
    /// <summary>
    /// UDP通信传输实现
    /// </summary>
    public class UdpTransport : BaseCommunicationTransport
    {
        /// <summary>
        /// UDP客户端
        /// </summary>
        private UdpClient? _udpClient;

        /// <summary>
        /// 远程端点
        /// </summary>
        private IPEndPoint? _remoteEndPoint;

        /// <summary>
        /// 本地端点
        /// </summary>
        private IPEndPoint? _localEndPoint;

        /// <summary>
        /// 传输类型
        /// </summary>
        public override string TransportType => "UDP";

        /// <summary>
        /// 接收超时时间（毫秒）
        /// </summary>
        public int ReceiveTimeout { get; set; } = 5000;

        /// <summary>
        /// 发送超时时间（毫秒）
        /// </summary>
        public int SendTimeout { get; set; } = 5000;

        /// <summary>
        /// 缓冲区大小
        /// </summary>
        public int BufferSize { get; set; } = 4096;

        /// <summary>
        /// 是否启用广播
        /// </summary>
        public bool EnableBroadcast { get; set; } = false;

        /// <summary>
        /// 是否重用地址
        /// </summary>
        public bool ReuseAddress { get; set; } = false;

        /// <summary>
        /// 本地端口（0表示自动分配）
        /// </summary>
        public int LocalPort { get; set; } = 0;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        public UdpTransport(ILogger<UdpTransport>? logger = null) : base(logger)
        {
        }

        /// <summary>
        /// 连接的具体实现
        /// </summary>
        /// <param name="connectionParameters">连接参数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>连接结果</returns>
        protected override async Task<CommunicationResult> ConnectInternalAsync(Dictionary<string, object> connectionParameters, CancellationToken cancellationToken)
        {
            try
            {
                // 获取连接参数
                var host = GetParameter<string>(connectionParameters, "Host", "127.0.0.1");
                var port = GetParameter<int>(connectionParameters, "Port", 502);
                LocalPort = GetParameter<int>(connectionParameters, "LocalPort", LocalPort);
                
                // 更新配置参数
                ReceiveTimeout = GetParameter<int>(connectionParameters, "ReceiveTimeout", ReceiveTimeout);
                SendTimeout = GetParameter<int>(connectionParameters, "SendTimeout", SendTimeout);
                BufferSize = GetParameter<int>(connectionParameters, "BufferSize", BufferSize);
                EnableBroadcast = GetParameter<bool>(connectionParameters, "EnableBroadcast", EnableBroadcast);
                ReuseAddress = GetParameter<bool>(connectionParameters, "ReuseAddress", ReuseAddress);

                LogDebug("开始UDP连接，主机: {Host}，端口: {Port}，本地端口: {LocalPort}", host, port, LocalPort);

                // 解析远程端点
                if (!IPAddress.TryParse(host, out var ipAddress))
                {
                    var hostEntry = await Dns.GetHostEntryAsync(host, cancellationToken);
                    ipAddress = hostEntry.AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork);
                    if (ipAddress == null)
                    {
                        return CommunicationResult.CreateFailure($"无法解析主机地址: {host}", "HostResolutionFailed");
                    }
                }

                _remoteEndPoint = new IPEndPoint(ipAddress, port);

                // 创建UDP客户端
                if (LocalPort > 0)
                {
                    _localEndPoint = new IPEndPoint(IPAddress.Any, LocalPort);
                    _udpClient = new UdpClient(_localEndPoint);
                }
                else
                {
                    _udpClient = new UdpClient();
                }

                // 配置UDP客户端
                _udpClient.Client.ReceiveTimeout = ReceiveTimeout;
                _udpClient.Client.SendTimeout = SendTimeout;

                if (EnableBroadcast)
                {
                    _udpClient.EnableBroadcast = true;
                }

                if (ReuseAddress)
                {
                    _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                }

                // 连接到远程端点（对于UDP，这只是设置默认目标）
                _udpClient.Connect(_remoteEndPoint);

                // 获取实际的本地端点
                _localEndPoint = _udpClient.Client.LocalEndPoint as IPEndPoint;

                LogInformation("UDP连接成功，远程端点: {RemoteEndPoint}，本地端点: {LocalEndPoint}", 
                    _remoteEndPoint, _localEndPoint);

                await Task.CompletedTask;
                return CommunicationResult.CreateSuccess("UDP连接成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "UDP连接时发生异常");
                
                // 清理资源
                CleanupConnection();
                
                return CommunicationResult.CreateFailure($"UDP连接异常: {ex.Message}", "ConnectionException", ex);
            }
        }

        /// <summary>
        /// 断开连接的具体实现
        /// </summary>
        /// <returns>断开结果</returns>
        protected override async Task<CommunicationResult> DisconnectInternalAsync()
        {
            try
            {
                LogDebug("开始断开UDP连接");

                CleanupConnection();

                LogInformation("UDP连接断开成功");
                await Task.CompletedTask;
                return CommunicationResult.CreateSuccess("UDP连接断开成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "断开UDP连接时发生异常");
                return CommunicationResult.CreateFailure($"断开UDP连接异常: {ex.Message}", "DisconnectionException", ex);
            }
        }

        /// <summary>
        /// 发送数据的具体实现
        /// </summary>
        /// <param name="data">数据</param>
        /// <returns>发送结果</returns>
        protected override CommunicationResult SendDataInternal(byte[] data)
        {
            try
            {
                if (_udpClient == null)
                {
                    return CommunicationResult.CreateFailure("UDP客户端未初始化", "ClientNotInitialized");
                }

                if (_remoteEndPoint == null)
                {
                    return CommunicationResult.CreateFailure("远程端点未设置", "RemoteEndPointNotSet");
                }

                LogDebug("发送UDP数据，远程端点: {RemoteEndPoint}，长度: {Length}，数据: {Data}", 
                    _remoteEndPoint, data.Length, Convert.ToHexString(data));

                var bytesSent = _udpClient.Send(data, data.Length);

                if (bytesSent != data.Length)
                {
                    return CommunicationResult.CreateFailure($"数据发送不完整，期望: {data.Length}，实际: {bytesSent}", "IncompleteSend");
                }

                LogDebug("UDP数据发送成功，远程端点: {RemoteEndPoint}，长度: {Length}", _remoteEndPoint, bytesSent);
                return CommunicationResult.CreateSuccess("UDP数据发送成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "发送UDP数据时发生异常");
                return CommunicationResult.CreateFailure($"发送UDP数据异常: {ex.Message}", "SendException", ex);
            }
        }

        /// <summary>
        /// 发送数据到指定端点
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="endPoint">目标端点</param>
        /// <returns>发送结果</returns>
        public CommunicationResult SendDataTo(byte[] data, IPEndPoint endPoint)
        {
            try
            {
                if (_udpClient == null)
                {
                    return CommunicationResult.CreateFailure("UDP客户端未初始化", "ClientNotInitialized");
                }

                LogDebug("发送UDP数据到指定端点，目标端点: {EndPoint}，长度: {Length}，数据: {Data}", 
                    endPoint, data.Length, Convert.ToHexString(data));

                var bytesSent = _udpClient.Send(data, data.Length, endPoint);

                if (bytesSent != data.Length)
                {
                    return CommunicationResult.CreateFailure($"数据发送不完整，期望: {data.Length}，实际: {bytesSent}", "IncompleteSend");
                }

                LogDebug("UDP数据发送成功，目标端点: {EndPoint}，长度: {Length}", endPoint, bytesSent);
                return CommunicationResult.CreateSuccess("UDP数据发送成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "发送UDP数据到指定端点时发生异常");
                return CommunicationResult.CreateFailure($"发送UDP数据异常: {ex.Message}", "SendException", ex);
            }
        }

        /// <summary>
        /// 配置参数的具体实现
        /// </summary>
        /// <param name="parameters">参数</param>
        /// <returns>配置结果</returns>
        protected override async Task<CommunicationResult> ConfigureInternalAsync(Dictionary<string, object> parameters)
        {
            try
            {
                LogDebug("开始配置UDP传输参数");

                // 更新配置参数
                ReceiveTimeout = GetParameter<int>(parameters, "ReceiveTimeout", ReceiveTimeout);
                SendTimeout = GetParameter<int>(parameters, "SendTimeout", SendTimeout);
                BufferSize = GetParameter<int>(parameters, "BufferSize", BufferSize);
                EnableBroadcast = GetParameter<bool>(parameters, "EnableBroadcast", EnableBroadcast);
                ReuseAddress = GetParameter<bool>(parameters, "ReuseAddress", ReuseAddress);

                // 如果已连接，更新UDP客户端的设置
                if (_udpClient != null)
                {
                    _udpClient.Client.ReceiveTimeout = ReceiveTimeout;
                    _udpClient.Client.SendTimeout = SendTimeout;
                    _udpClient.EnableBroadcast = EnableBroadcast;

                    if (ReuseAddress)
                    {
                        _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                    }
                }

                LogDebug("UDP传输参数配置完成");
                await Task.CompletedTask;
                return CommunicationResult.CreateSuccess("UDP传输参数配置成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "配置UDP传输参数时发生异常");
                return CommunicationResult.CreateFailure($"配置UDP传输参数异常: {ex.Message}", "ConfigurationException", ex);
            }
        }

        /// <summary>
        /// 数据接收循环
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>任务</returns>
        protected override async Task ReceiveDataLoopAsync(CancellationToken cancellationToken)
        {
            try
            {
                LogDebug("开始UDP数据接收循环，缓冲区大小: {BufferSize}", BufferSize);

                while (!cancellationToken.IsCancellationRequested && IsConnected && _udpClient != null)
                {
                    try
                    {
                        // 接收数据
                        var result = await _udpClient.ReceiveAsync(cancellationToken);
                        var data = result.Buffer;
                        var remoteEndPoint = result.RemoteEndPoint;

                        if (data.Length > 0)
                        {
                            LogDebug("接收到UDP数据，来源端点: {RemoteEndPoint}，长度: {Length}，数据: {Data}", 
                                remoteEndPoint, data.Length, Convert.ToHexString(data));

                            OnDataReceived(data);
                        }
                    }
                    catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
                    {
                        LogDebug("UDP数据接收循环被取消");
                        break;
                    }
                    catch (ObjectDisposedException)
                    {
                        LogDebug("UDP客户端已释放，退出接收循环");
                        break;
                    }
                    catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut)
                    {
                        // 接收超时是正常的，继续循环
                        continue;
                    }
                    catch (Exception ex)
                    {
                        LogError(ex, "UDP数据接收时发生异常");
                        await Task.Delay(1000, cancellationToken); // 等待一段时间后重试
                    }
                }

                LogDebug("UDP数据接收循环结束");
            }
            catch (Exception ex)
            {
                LogError(ex, "UDP数据接收循环发生异常");
            }
        }

        /// <summary>
        /// 构建连接信息
        /// </summary>
        /// <param name="connectionParameters">连接参数</param>
        /// <returns>连接信息</returns>
        protected override string BuildConnectionInfo(Dictionary<string, object> connectionParameters)
        {
            var host = GetParameter<string>(connectionParameters, "Host", "127.0.0.1");
            var port = GetParameter<int>(connectionParameters, "Port", 502);
            var localPort = GetParameter<int>(connectionParameters, "LocalPort", 0);
            
            if (localPort > 0)
            {
                return $"UDP://{host}:{port} (Local:{localPort})";
            }
            else
            {
                return $"UDP://{host}:{port}";
            }
        }

        /// <summary>
        /// 释放资源的具体实现
        /// </summary>
        protected override void DisposeInternal()
        {
            CleanupConnection();
        }

        #region 私有方法

        /// <summary>
        /// 清理连接资源
        /// </summary>
        private void CleanupConnection()
        {
            try
            {
                _udpClient?.Close();
                _udpClient?.Dispose();
                _udpClient = null;
                _remoteEndPoint = null;
                _localEndPoint = null;

                LogDebug("UDP连接资源清理完成");
            }
            catch (Exception ex)
            {
                LogError(ex, "清理UDP连接资源时发生异常");
            }
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 获取本地端点信息
        /// </summary>
        /// <returns>本地端点</returns>
        public IPEndPoint? GetLocalEndPoint()
        {
            return _localEndPoint;
        }

        /// <summary>
        /// 获取远程端点信息
        /// </summary>
        /// <returns>远程端点</returns>
        public IPEndPoint? GetRemoteEndPoint()
        {
            return _remoteEndPoint;
        }

        /// <summary>
        /// 设置远程端点
        /// </summary>
        /// <param name="endPoint">远程端点</param>
        public void SetRemoteEndPoint(IPEndPoint endPoint)
        {
            _remoteEndPoint = endPoint;
            
            if (_udpClient != null)
            {
                try
                {
                    _udpClient.Connect(endPoint);
                    LogDebug("远程端点设置成功: {EndPoint}", endPoint);
                }
                catch (Exception ex)
                {
                    LogError(ex, "设置远程端点时发生异常: {EndPoint}", endPoint);
                }
            }
        }

        /// <summary>
        /// 检查连接状态
        /// </summary>
        /// <returns>连接是否有效</returns>
        public bool IsConnectionHealthy()
        {
            try
            {
                return _udpClient != null && _remoteEndPoint != null;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 获取连接统计信息
        /// </summary>
        /// <returns>统计信息</returns>
        public Dictionary<string, object> GetConnectionStats()
        {
            var stats = new Dictionary<string, object>
            {
                ["TransportType"] = TransportType,
                ["IsConnected"] = IsConnected,
                ["IsHealthy"] = IsConnectionHealthy(),
                ["ReceiveTimeout"] = ReceiveTimeout,
                ["SendTimeout"] = SendTimeout,
                ["BufferSize"] = BufferSize,
                ["EnableBroadcast"] = EnableBroadcast,
                ["ReuseAddress"] = ReuseAddress,
                ["LocalPort"] = LocalPort
            };

            if (_localEndPoint != null)
            {
                stats["LocalEndPoint"] = _localEndPoint.ToString();
            }

            if (_remoteEndPoint != null)
            {
                stats["RemoteEndPoint"] = _remoteEndPoint.ToString();
            }

            return stats;
        }

        /// <summary>
        /// 广播数据
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="port">目标端口</param>
        /// <returns>发送结果</returns>
        public CommunicationResult BroadcastData(byte[] data, int port)
        {
            try
            {
                if (!EnableBroadcast)
                {
                    return CommunicationResult.CreateFailure("广播功能未启用", "BroadcastNotEnabled");
                }

                var broadcastEndPoint = new IPEndPoint(IPAddress.Broadcast, port);
                return SendDataTo(data, broadcastEndPoint);
            }
            catch (Exception ex)
            {
                LogError(ex, "广播UDP数据时发生异常");
                return CommunicationResult.CreateFailure($"广播UDP数据异常: {ex.Message}", "BroadcastException", ex);
            }
        }

        /// <summary>
        /// 多播数据
        /// </summary>
        /// <param name="data">数据</param>
        /// <param name="multicastAddress">多播地址</param>
        /// <param name="port">目标端口</param>
        /// <returns>发送结果</returns>
        public CommunicationResult MulticastData(byte[] data, IPAddress multicastAddress, int port)
        {
            try
            {
                if (!IsMulticastAddress(multicastAddress))
                {
                    return CommunicationResult.CreateFailure("无效的多播地址", "InvalidMulticastAddress");
                }

                var multicastEndPoint = new IPEndPoint(multicastAddress, port);
                return SendDataTo(data, multicastEndPoint);
            }
            catch (Exception ex)
            {
                LogError(ex, "多播UDP数据时发生异常");
                return CommunicationResult.CreateFailure($"多播UDP数据异常: {ex.Message}", "MulticastException", ex);
            }
        }

        /// <summary>
        /// 检查IP地址是否为组播地址
        /// </summary>
        /// <param name="address">IP地址</param>
        /// <returns>是否为组播地址</returns>
        private static bool IsMulticastAddress(IPAddress address)
        {
            if (address.AddressFamily == AddressFamily.InterNetwork)
            {
                // IPv4组播地址范围：224.0.0.0 - 239.255.255.255
                var bytes = address.GetAddressBytes();
                return bytes[0] >= 224 && bytes[0] <= 239;
            }
            else if (address.AddressFamily == AddressFamily.InterNetworkV6)
            {
                // IPv6组播地址以FF开头
                var bytes = address.GetAddressBytes();
                return bytes[0] == 0xFF;
            }
            return false;
        }

        #endregion
    }
}